package com.system.business.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.util.EnumUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.system.business.domain.ConfirmOrder;
import com.system.business.domain.DailyTrainCarriage;
import com.system.business.domain.DailyTrainSeat;
import com.system.business.domain.DailyTrainTicket;
import com.system.business.enums.ConfirmOrderStatusEnum;
import com.system.business.mapper.cust.DailyTrainTicketMapperCust;
import com.system.business.req.ConfirmOrderDoReq;
import com.system.business.req.ConfirmOrderQueryReq;
import com.system.business.req.ConfirmOrderSaveReq;
import com.system.business.req.ConfirmOrderTicketReq;
import com.system.business.resp.ConfirmOrderQueryResp;
import com.system.business.service.ConfirmOrderService;
import com.system.business.mapper.ConfirmOrderMapper;
import com.system.business.service.DailyTrainCarriageService;
import com.system.business.service.DailyTrainSeatService;
import com.system.business.service.DailyTrainTicketService;
import com.system.common.context.LoginMemberContext;
import com.system.common.exception.BusinessException;
import com.system.common.exception.BusinessExceptionEnum;
import com.system.common.resp.PageResp;
import com.system.common.utils.SnowUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.ListResourceBundle;

/**
 * @author Admin
 * @description 针对表【confirm_order(确认订单)】的数据库操作Service实现
 * @createDate 2024-03-21 15:02:15
 */
@Service
public class ConfirmOrderServiceImpl extends ServiceImpl<ConfirmOrderMapper, ConfirmOrder>
        implements ConfirmOrderService {
    private static final Logger LOG = LoggerFactory.getLogger(ConfirmOrderService.class);

    @Autowired
    private ConfirmOrderMapper confirmOrderMapper;
    @Autowired
    private DailyTrainTicketService dailyTrainTicketService;
    @Autowired
    private DailyTrainCarriageService dailyTrainCarriageService;
    @Autowired
    private DailyTrainSeatService dailyTrainSeatService;
    @Autowired
    private DailyTrainTicketMapperCust dailyTrainTicketMapperCust;

    @Override
    public void save(ConfirmOrderSaveReq req) {
        DateTime now = DateTime.now();

        ConfirmOrder confirmOrder = BeanUtil.copyProperties(req, ConfirmOrder.class);
        if (ObjectUtil.isNull(confirmOrder.getId())) {
            confirmOrder.setId(SnowUtil.getSnowflakeNextId());
            confirmOrder.setCreateTime(now);
            confirmOrder.setUpdateTime(now);
            confirmOrderMapper.insert(confirmOrder);
        } else {
            confirmOrder.setUpdateTime(now);
            confirmOrderMapper.updateById(confirmOrder);
        }
    }

    @Override
    public PageResp<ConfirmOrderQueryResp> queryList(ConfirmOrderQueryReq req) {
        Page<ConfirmOrder> pageCondition = new Page<>(req.getPage(), req.getSize());
        QueryWrapper<ConfirmOrder> passengerQueryWrapper = new QueryWrapper<>();
        Page<ConfirmOrder> pageData = confirmOrderMapper.selectPage(pageCondition, passengerQueryWrapper);
        List<ConfirmOrderQueryResp> list = BeanUtil.copyToList(pageData.getRecords(), ConfirmOrderQueryResp.class);

        PageResp<ConfirmOrderQueryResp> pageResp = new PageResp<>();
        pageResp.setTotal(pageData.getTotal());
        pageResp.setList(list);
        return pageResp;
    }

    @Override
    public void doConfirm(ConfirmOrderDoReq req) {
        //TODO 省略业务校验，如车次是否存在 余票是否存在 车次是否在有效期内

        // 保存确认订单，状态初始
        Date date = req.getDate();
        String trainCode = req.getTrainCode();
        String start = req.getStart();
        String end = req.getEnd();
        List<ConfirmOrderTicketReq> tickets = req.getTickets();

        ConfirmOrder confirmOrder = new ConfirmOrder();
        DateTime now = DateTime.now();
        confirmOrder.setMemberId(LoginMemberContext.getId());
        confirmOrder.setId(SnowUtil.getSnowflakeNextId());
        confirmOrder.setCreateTime(now);
        confirmOrder.setUpdateTime(now);
        confirmOrder.setDate(date);
        confirmOrder.setTrainCode(trainCode);
        confirmOrder.setStart(start);
        confirmOrder.setEnd(end);
        confirmOrder.setDailyTrainTicketId(req.getDailyTrainTicketId());
        confirmOrder.setStatus(ConfirmOrderStatusEnum.INIT.getCode());
        confirmOrder.setTickets(JSON.toJSONString(tickets));
        confirmOrderMapper.insert(confirmOrder);

        //查出余票记录，得到真实库存
        DailyTrainTicket dailyTrainTicket = dailyTrainTicketService.selectByUnique(date, trainCode, start, end);
        System.out.println("dailyTrainTicket:" + dailyTrainTicket);

        //扣减余票数量,并判断余票是否足够
        reduceTickets(req,dailyTrainTicket);
    }


    private  void reduceTickets(ConfirmOrderDoReq req, DailyTrainTicket dailyTrainTicket) {
        for (ConfirmOrderTicketReq ticketReq : req.getTickets()) {
            DailyTrainSeat dailyTrainSeat = dailyTrainSeatService.selectByNotSell(req.getDate(), req.getTrainCode(), ticketReq.getSeatTypeCode());
            calSell(dailyTrainSeat,dailyTrainTicket.getStartIndex(),dailyTrainTicket.getEndIndex());

            Integer startIndex = dailyTrainTicket.getStartIndex();
            Integer endIndex = dailyTrainTicket.getEndIndex();
            char[] chars = dailyTrainSeat.getSell().toCharArray();
            Integer maxStartIndex = endIndex - 1;
            Integer minEndIndex = startIndex + 1;
            Integer minStartIndex = 0;
            for (int i = startIndex - 1; i >= 0; i--) {
                char aChar = chars[i];
                if (aChar == '1') {
                    minStartIndex = i + 1;
                    break;
                }
            }
            LOG.info("影响出发站区间：" + minStartIndex + "-" + maxStartIndex);

            Integer maxEndIndex = dailyTrainSeat.getSell().length();
            for (int i = endIndex; i < dailyTrainSeat.getSell().length(); i++) {
                char aChar = chars[i];
                if (aChar == '1') {
                    maxEndIndex = i;
                    break;
                }
            }
            LOG.info("影响到达站区间：" + minEndIndex + "-" + maxEndIndex);

            dailyTrainTicketMapperCust.updateCountBySell(
                    dailyTrainSeat.getDate(),
                    dailyTrainSeat.getTrainCode(),
                    dailyTrainSeat.getSeatType(),
                    minStartIndex,
                    maxStartIndex,
                    minEndIndex,
                    maxEndIndex);
            dailyTrainSeatService.updateById(dailyTrainSeat);
        }
    }

    private boolean calSell(DailyTrainSeat dailyTrainSeat, Integer startIndex, Integer endIndex) {
        // 00001, 00000
        String sell = dailyTrainSeat.getSell();
        //  000, 000
        String sellPart = sell.substring(startIndex, endIndex);
        if (Integer.parseInt(sellPart) > 0) {
            LOG.info("座位{}在本次车站区间{}~{}已售过票，不可选中该座位", dailyTrainSeat.getCarriageSeatIndex(), startIndex, endIndex);
            return false;
        } else {
            LOG.info("座位{}在本次车站区间{}~{}未售过票，可选中该座位", dailyTrainSeat.getCarriageSeatIndex(), startIndex, endIndex);
            //  111,   111
            String curSell = sellPart.replace('0', '1');
            // 0111,  0111
            curSell = StrUtil.fillBefore(curSell, '0', endIndex);
            // 01110, 01110
            curSell = StrUtil.fillAfter(curSell, '0', sell.length());

            // 当前区间售票信息curSell 01110与库里的已售信息sell 00001按位与，即可得到该座位卖出此票后的售票详情
            // 15(01111), 14(01110 = 01110|00000)
            int newSellInt = NumberUtil.binaryToInt(curSell) | NumberUtil.binaryToInt(sell);
            //  1111,  1110
            String newSell = NumberUtil.getBinaryStr(newSellInt);
            // 01111, 01110
            newSell = StrUtil.fillBefore(newSell, '0', sell.length());
            LOG.info("座位{}被选中，原售票信息：{}，车站区间：{}~{}，即：{}，最终售票信息：{}"
                    , dailyTrainSeat.getCarriageSeatIndex(), sell, startIndex, endIndex, curSell, newSell);
            dailyTrainSeat.setSell(newSell);
            return true;

        }
    }
}




